from kubernetes_asyncio import client

from balder.services.kube_base import KubeBase


class IngressService(KubeBase):
    async def create_ingress(self, service: client.V1Service, namespace: str, name: str, host: str, path: str, path_type: str) -> client.V1Ingress:
        # 通过 kubernetes 新建一个 ingress 资源
        ingress = client.V1Ingress(
            api_version="networking.k8s.io/v1",
            kind="Ingress",
            metadata=client.V1ObjectMeta(name=name),
            spec=client.V1IngressSpec(
                rules=[
                    client.V1IngressRule(
                        host=host,
                        http=client.V1HTTPIngressRuleValue(
                            paths=[
                                client.V1HTTPIngressPath(
                                    path=path,
                                    backend=client.V1IngressBackend(
                                        service=client.V1IngressServiceBackend(
                                            name=service.metadata.name,
                                            port=client.V1ServiceBackendPort(
                                                number=service.spec.ports[0].port
                                            )
                                        )
                                    ),
                                    path_type=path_type
                                )
                            ]
                        )
                    )
                ]
            )
        )

        # 新建 ingress
        await self.networking_v1_api.create_namespaced_ingress(namespace=namespace, body=ingress)

        return ingress

    async def delete_ingress(self, namespace: str, name: str) -> client.V1Status:
        # 通过 kubernetes 删除一个 ingress 资源
        return await self.networking_v1_api.delete_namespaced_ingress(namespace=namespace, name=name)

    async def get_ingress(self, namespace: str, name: str) -> client.V1Ingress:
        return await self.networking_v1_api.read_namespaced_ingress(namespace=namespace, name=name)

    async def get_ingress_list(self, namespace: str) -> client.V1IngressList:
        return await self.networking_v1_api.list_namespaced_ingress(namespace=namespace)

    # 添加规则
    async def add_rule(self, namespace: str, name: str, host: str, path: str, path_type: str, service: client.V1Service) -> client.V1Ingress:
        # 获取 ingress
        ingress = await self.get_ingress(namespace=namespace, name=name)

        # 添加规则
        ingress.spec.rules.append(
            client.V1IngressRule(
                host=host,
                http=client.V1HTTPIngressRuleValue(
                    paths=[
                        client.V1HTTPIngressPath(
                            path=path,
                            backend=client.V1IngressBackend(
                                service=client.V1IngressServiceBackend(
                                    name=service.metadata.name,
                                    port=client.V1ServiceBackendPort(
                                        number=service.spec.ports[0].port
                                    )
                                )
                            ),
                            path_type=path_type
                        )
                    ]
                )
            )
        )

        # 更新 ingress
        return await self.networking_v1_api.replace_namespaced_ingress(namespace=ingress.metadata.namespace, name=ingress.metadata.name, body=ingress)

    # 删除规则
    async def delete_rule(self, namespace: str, name: str, host: str) -> client.V1Ingress:
        # 获取 ingress
        ingress = await self.get_ingress(namespace=namespace, name=name)

        # 删除规则
        for rule in ingress.spec.rules:
            if rule.host == host:
                ingress.spec.rules.remove(rule)
                break

        # 更新 ingress
        return await self.networking_v1_api.replace_namespaced_ingress(namespace=ingress.metadata.namespace, name=ingress.metadata.name, body=ingress)

    # 添加指定host的后端服务
    async def add_backend(self, namespace: str, name: str, host: str, path: str, path_type: str, service: client.V1Service) -> client.V1Ingress:
        # 获取 ingress
        ingress = await self.get_ingress(namespace=namespace, name=name)

        # 添加后端服务
        for rule in ingress.spec.rules:
            if rule.host == host:
                rule.http.paths.append(
                    client.V1HTTPIngressPath(
                        path=path,
                        backend=client.V1IngressBackend(
                            service=client.V1IngressServiceBackend(
                                name=service.metadata.name,
                                port=client.V1ServiceBackendPort(
                                    number=service.spec.ports[0].port
                                )
                            )
                        ),
                        path_type=path_type
                    )
                )
                break

        # 更新 ingress
        return await self.networking_v1_api.replace_namespaced_ingress(namespace=ingress.metadata.namespace, name=ingress.metadata.name, body=ingress)

    # 删除指定host的后端服务
    async def delete_backend(self, namespace: str, name: str, host: str, path: str) -> client.V1Ingress:
        # 获取 ingress
        ingress = await self.get_ingress(namespace=namespace, name=name)

        # 删除后端服务
        for rule in ingress.spec.rules:
            if rule.host == host:
                for path_item in rule.http.paths:
                    if path_item.path == path:
                        rule.http.paths.remove(path_item)
                        break
                break

        # 更新 ingress
        return await self.networking_v1_api.replace_namespaced_ingress(namespace=ingress.metadata.namespace, name=ingress.metadata.name, body=ingress)
